package com.firefly.admin.common.utils;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;

public class Sm2Util {
    private static final String PRIVATE_KEY = "187443149646162d166abe07ffd8f00592f13cded2c28977f74145f3f40753ee";
    private static final String PUBLIC_KEY = "04ead43cac51eda3013d9db63323f8532e23baf744ac852356dff9fa4f244d1d8a45ba6b758d5bd15434c2ed1cc198188c4493ae8b219c262a3b79eab93f4d21c4";

    /**
     * 生成公钥、私钥，这个保存好，尤其是私钥，切记不可泄漏
     */
    public static void generateCommonKey() {
        SM2 sm2 = SmUtil.sm2();
        // 私钥：这个保存好，切记不要泄漏，真的泄露了就重新生成一下
        byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
        // 公钥：这个是前后端加密用的，不压缩选择带04的，不带04到时候前端会报错
        byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
        Console.log("公钥：\n{}", HexUtil.encodeHexStr(publicKey));
        Console.log("私钥：\n{}", HexUtil.encodeHexStr(privateKey));
    }

    public static void main(String[] args) throws Exception {
        String encrypt = encryptData("jdbc:mysql://47.110.225.228:3306/firefly_template?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8");
        System.out.println("encrypt = " + encrypt);
        String decrypt = decryptData("49f5fd4b1e96c36c31dfa0bd76d00e8f6f648c2ae62074445f1c5a51b776262d8a72228b4e046bfd2130de3e2db191e03f17bab1483de3779cda48e357909c0db013764530fc3e22e9e78d5806aa5160e5ea6cdf5eac2813c52290c0cc97b288181a0eaa972807299f035dd3a21a32d2424ed1704687ebcad8808702326d915e23be1e16e0821547");
        System.out.println("decrypt = " + decrypt);
    }

    /**
     * sm2明文加密
     * PRIVATE_KEY:生成的私钥
     * PUBLIC_KEY：生成的公钥
     *
     * @param data 加密前的明文
     * @return 加密后的密文
     */

    public static String encryptData(String data) {
        SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
        String encryptBcd = sm2.encryptBcd(data, KeyType.PublicKey);
        // 这里的处理前端也可以处理，这个就看怎么约定了，其实都无伤大雅
        if (StrUtil.isNotBlank(encryptBcd)) {
            // 生成的加密密文会带04，因为前端sm-crypto默认的是1-C1C3C2模式，这里需去除04才能正常解密
            if (encryptBcd.startsWith("04")) {
                encryptBcd = encryptBcd.substring(2);
            }
            // 前端解密时只能解纯小写形式的16进制数据，这里需要将所有大写字母转化为小写
            encryptBcd = encryptBcd.toLowerCase();
        }
        return encryptBcd;
    }

    /**
     * sm2密文解密
     * PRIVATE_KEY:生成的私钥
     * PUBLIC_KEY：生成的公钥
     *
     * @param encryptData 加密密文
     * @return 解密后的明文字符串
     */

    public static String decryptData(String encryptData) {
        if (StrUtil.isBlank(encryptData)) {
            throw new RuntimeException("解密串为空，解密失败");
        }
        SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
        // BC库解密时密文开头必须带04，如果没带04则需补齐
        if (!encryptData.startsWith("04")) {
            encryptData = "04".concat(encryptData);
        }
        byte[] decryptFromBcd = sm2.decryptFromBcd(encryptData, KeyType.PrivateKey);
        if (decryptFromBcd != null && decryptFromBcd.length > 0) {
            return StrUtil.utf8Str(decryptFromBcd);
        } else {
            return encryptData;
        }
    }

}
